package com.share.netdisk.garbage.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.share.netdisk.config.HdfsConfig;
import com.share.netdisk.garbage.dao.GarbageDao;
import com.share.netdisk.garbage.model.Garbage;
import com.share.netdisk.reclaim.dao.ReclaimDao;
import com.share.netdisk.reclaim.model.Reclaim;
import com.share.netdisk.userhomefile.dao.UserHomeFileDao;
import com.share.netdisk.userhomefile.model.UserHomeFile;
import lombok.extern.slf4j.Slf4j;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Slf4j
@Service
public class GarbageServiceImpl extends ServiceImpl<GarbageDao, Garbage> implements GarbageService {

	@Autowired
	private HdfsConfig hdfsConfig;//hdfs路径

	@Autowired
	private ReclaimDao reclaimDao;//回收站表

	@Autowired
	private GarbageDao garbageDao;//文件表

	@Autowired
	private UserHomeFileDao userHomeFileDao;


	/**
	 * 根据回收站id批量恢复文件
	 * 1.首先根据reclaimID找到home_file_id(user_id)和file_id，
	 * 2.根据file_id从file表修改file表中的文件状态和回收站状态都为1
	 * 3.再根据file_id从user_home_file表中home_file_id(file_id)获取到hdfs的recycle路径和home路径，把文件移动回去
	 * 4.修改reclaim表中的状态为0。
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<Integer, String> restoreFilesByReclaimId(List<Integer> reclaimIds) {
		Map<Integer, String> failures = new HashMap<>();

		for (Integer reclaimId : reclaimIds) {
			try {
				// 1. 根据 reclaimID 找到 home_file_id(user_id) 和 file_id
				QueryWrapper<Reclaim> queryWrapper = new QueryWrapper<>();
				queryWrapper.eq("reclaim_id", reclaimId);
				Reclaim reclaimRecord = reclaimDao.selectOne(queryWrapper);
				if (reclaimRecord == null || reclaimRecord.getFileId() == null || reclaimRecord.getHomeFileId() == null) {
					log.warn("Reclaim ID {} not found or file ID/home_file_id is invalid.", reclaimId);
					failures.put(reclaimId, "回收站记录未找																															到或文件ID/用户ID无效");
					continue;
				}
				Integer fileId = reclaimRecord.getFileId(); // 获取 file_id
				Integer homeFileId = reclaimRecord.getHomeFileId(); // 获取 home_file_id,这里是user_id

				// 2. 使用 file_id 查找 file 表中的记录
				Garbage fileInfo = garbageDao.selectById(fileId);
				if (fileInfo == null || fileInfo.getFileUrl() == null) {
					log.warn("File ID {} not found in file table or file URL is missing for reclaim ID {}.", fileId, reclaimId);
					failures.put(reclaimId, "文件路径信息缺失");
					continue;
				}

				// 使用 QueryWrapper 来构建条件查询
				// 3. 使用 file_id 查找 user_home_file 表中 home_file_id(file_id) 的记录
				QueryWrapper<UserHomeFile> queryWrapper1 = new QueryWrapper<>();
				queryWrapper1.eq("home_file_id", fileId); // 查找 home_file_id 与 file_id 相等的记录
				UserHomeFile userHomeFile = userHomeFileDao.selectOne(queryWrapper1);
				if (userHomeFile == null || userHomeFile.getReclaimUrl() == null) {
					log.warn("User home file record not found or reclaim URL is missing for home_file_id {} and reclaim ID {}.", homeFileId, reclaimId);
					failures.put(reclaimId, "缺少必要的路径信息");
					continue;
				}

				// 4. 获取原始路径和回收站路径的 URL
				String originalUrl = userHomeFile.getHomeFileUrl();
				String reclaimUrl = userHomeFile.getReclaimUrl();

				if (originalUrl == null || reclaimUrl == null) {
					log.warn("File ID {} has missing URL information for reclaim ID {}.", fileId, reclaimId);
					failures.put(reclaimId, "缺少必要的路径信息");
					continue;
				}

				// 构建 Path 对象
				Path originalPath = new Path(originalUrl);
				Path trashPath = new Path(reclaimUrl);

				// 5. 获取 HDFS 文件系统实例
				FileSystem fs = FileSystem.get(hdfsConfig.fileSystem().getConf());  // 获取 HDFS 配置

				// 6. 检查文件是否存在，并执行文件移动
				if (fs.exists(trashPath)) {
					// 先检查目标路径是否已经存在文件，防止覆盖
					if (fs.exists(originalPath)) {
						log.warn("Target file already exists at {}. Overwriting file.", originalPath);
						boolean deleteResult = fs.delete(originalPath, true);  // 删除已存在的文件
						if (!deleteResult) {
							log.warn("Failed to delete existing file at {} before restoring.", originalPath);
							failures.put(reclaimId, "目标路径已存在文件，删除失败");
							continue;
						}
					}

					// 执行文件恢复
					boolean isMoved = fs.rename(trashPath, originalPath);  // 使用 HDFS 的 rename 方法
					if (!isMoved) {
						log.warn("Failed to rename file ID {} from {} to {} for reclaim ID {}.", fileId, trashPath, originalPath, reclaimId);
						failures.put(reclaimId, "文件重命名失败");
						continue;
					}
					log.info("File ID {} successfully restored from HDFS for reclaim ID {}.", fileId, reclaimId);
				} else {
					log.warn("File ID {} not found in HDFS trash path: {} for reclaim ID {}.", fileId, trashPath, reclaimId);
					failures.put(reclaimId, "文件在HDFS回收站中不存在");
					continue;
				}

				// 7. 更新file表中的文件状态为 1（正常）
				LambdaUpdateWrapper<Garbage> updateWrapper = new LambdaUpdateWrapper<>();
				updateWrapper.eq(Garbage::getFileId, fileId) // 确保只更新当前文件
						.set(Garbage::getFileStatus, 1)
						.set(Garbage::getReclaimStatus, 1); // 恢复文件状态为 1（正常）
				garbageDao.update(null, updateWrapper);

				// 8. 更新回收站表中的状态 0（不删除，只修改状态）
				LambdaUpdateWrapper<Reclaim> reclaimUpdateWrapper = new LambdaUpdateWrapper<>();
				reclaimUpdateWrapper.eq(Reclaim::getReclaimId, reclaimId)
						.set(Reclaim::getReclaimStatus, 0); // 更新回收站状态为 0（恢复）
				reclaimDao.update(null, reclaimUpdateWrapper);

				log.info("Reclaim record with reclaim ID {} has been deleted.", reclaimId);

			} catch (IOException e) {
				log.error("Failed to restore file with reclaim ID {} due to HDFS operation error: {}", reclaimId, e.getMessage(), e);
				failures.put(reclaimId, "HDFS操作错误：" + e.getMessage());
			} catch (Exception e) {
				log.error("Unexpected error restoring file with reclaim ID {}: {}", reclaimId, e.getMessage(), e);
				failures.put(reclaimId, "意外错误：" + e.getMessage());
			}
		}

		return failures;
	}
}
